package gmu.swe.project.registry;

import gmu.swe.project.tracker.TrackerInfo;
import gmu.swe.project.utils.Helper;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

import static java.util.concurrent.TimeUnit.*;

public class KeepAliveServiceThread extends Thread {

	int interval = 0;
	final ScheduledExecutorService scheduler = Executors
			.newScheduledThreadPool(1);
	private static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss";
	SimpleDateFormat dfm = new SimpleDateFormat(DATE_FORMAT_NOW);

	KeepAliveServiceThread(int intervalArg) {
		super("KeepAliveServiceThread");
		this.interval = intervalArg;
	}// KeepAliveServiceThread

	public void run() {

		System.out.println("KeepAliveServiceThread::run()::KeepAliveService thread spawned");

		checkTrackerRegistration();
	}// run

	/**
	 * The scheduler that is currently set to start immediately, and execute
	 * every X seconds. The process is to check the current tracker registration
	 * and make sure that all current trackers have sent a keep alive message
	 * within the last X seconds, if any tracker did not send a message within
	 * the time-frame, those trackers will be removed from the tracker
	 * registration and considered no longer in the network
	 */
	public void checkTrackerRegistration() {
		final Runnable keepAlive = new Runnable() {
			public void run() {
				Date time = Helper.getCurrTime();
				System.out.println("****************************************");
				System.out.println("KeepAliveServiceThread::run()::Check TrackerRegistration every "
								+ Integer.toString(interval) + " seconds");
				System.out.println("KeepAliveServiceThread::run()::Current time: "
								+ dfm.format(time));
				processTrackerRegistration(time);
				
				RegistryServer.getTrackerRegistration().printMe();
			}
		};
		scheduler.scheduleAtFixedRate(keepAlive, 0, interval, SECONDS);

	}// checkTrackerRegistration

	/**
	 * Iterate through the main tracker registration and check the time-stamp of
	 * each tracker, ensuring that each tracker has a valid time-stamp within
	 * the last "X" seconds
	 */
	private void processTrackerRegistration(Date currTime) {
		System.out.println("KeepAliveServiceThread::processTrackerRegistration()");
		TrackerRegistration tmpTr = RegistryServer.getTrackerRegistration();
		boolean dirty = false;

		try {
			Iterator<TrackerInfo> trIter = tmpTr.iterator();
			while (tmpTr.getTrackerSet().size() > 0 && trIter.hasNext()) {
				TrackerInfo tracker = (TrackerInfo) trIter.next();
				Date trackerTime = tracker.getTimestamp();
				if (Helper.compareTime(currTime.getTime(), trackerTime.getTime()) > interval) {
					System.out.println("KeepAliveServiceThread::processTrackerRegistration():found OUT-DATED tracker");
					dirty = true;
					//tmpTr.removeTracker(tracker);
					tmpTr.getTrackerSet().remove(tracker);
				}
			}// while
			if (dirty) {
				System.out.println("KeepAliveServiceThread::processTrackerRegistration():reset the tracker registration");
				RegistryServer.setTrackerRegistration(tmpTr);
			}
		} catch(Exception ex) {
			System.out.println("KeepAliveServiceThread::encountered exception " + ex.getStackTrace());
		}
		System.out.println("KeepAliveServiceThread::processTrackerRegistration():Done processing");
	}// processTrackerRegistration

	/**
	 * Compare the current time with each tracker's time
	 * 
	 * @param currTime
	 * @param trackerTime
	 * @return
	 */
	private long compareTime(long currTime, long trackerTime) {
		// right now we are comparing in seconds, divide by 60 if you want to
		// compare in minutes
		long timeDiff = (Math.abs((currTime - trackerTime) / 1000));
		System.out.println("KeepAliveServiceThread::compareTime():timeDiff: "
				+ Long.toString(timeDiff));
		return timeDiff;
	}// compareTime


}// class KeepAliveThread
